﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEngine.UI;
using System.Diagnostics;
using Debug = UnityEngine.Debug;
using Button = UnityEngine.UI.Button;
using System.Text;
using System;
using UnityEngine.Networking;

namespace CreatPart
{
    public enum LoadingState
    {
        Version,
        Download,
        Update,
        Open,
    }

    #region Serializable

    [Serializable]
    public class LocalConfigData
    {
        public string Version; //版本号
        public string LocalRootURL;//安装文件的路径
        public string URL; //服务器配置文件的路径
        public string ExeName; //启动文件的名称
        public string InstallPackageUrl; //安装包路径
        public string AssetBundlsUrl; //Assetbundls
        public string StreamingAssetsUrl; //StreamingAssetsUrl 

        //字典用来后续修改更新用
        public List<AssetsDictionary> AssetBundleList;
        public List<AssetsDictionary> StreamAssetsList;
    }

    [Serializable]
    public class AssetsDictionary
    {
        public string Path;
        public string Version;

        public AssetsDictionary(string path, string version)
        {
            Path = path; Version = version;
        }
    }


    [Serializable]
    public class WebConfigData
    {
        public string Version; //版本号
        public string WebUrlRoot; //根目录
        public string PackageName;  //安装包名称
        public string InstallPackageUrl; //安装包路径
        public string AssetBundlsUrl; //Assetbundls
        public string StreamingAssetsUrl; //StreamingAssetsUrl 

        //字典用来后续修改更新用
        public List<AssetsDictionary> AssetBundleList;
        public List<AssetsDictionary> StreamAssetsList;


    }
    #endregion

    public class MainManager : MonoBehaviour
    {
        #region veriable

        private LocalConfigData mConfigData;
        private WebConfigData mWebConfigData;
        private LoadingState mLoadState = LoadingState.Version;
        private LoadingState LoadState
        {
            set
            {
                if (mLoadState != value)
                {
                    if (value == LoadingState.Download)
                    {
                        mLoadingText.text = "正在下载，请稍候...";
                    }
                    else if (value == LoadingState.Update)
                    {
                        mLoadingText.text = "正在更新，请稍候...";
                    }
                    else if (value == LoadingState.Version)
                    {
                        mLoadingText.text = "正在校验版本信息...";
                    }
                    else if (value == LoadingState.Open)
                    {
                        mLoadingText.text = "正在启动软件...";
                    }
                }
            }

            get { return mLoadState; }
        }

        private string mLocalRootUrl;

        private Transform mLoadingPanel;
        private Text mLoadingText;

        private Transform mInstallPanel;
        private Transform mSelectUrlPanel;
        private Transform mInstallLoadingPanel;
        private Button mInstallBtn;
        private Button mChangeUrlBtn;
        private Text mUrlText;
        private Slider mLoadingSlider;
        private Text mInstallText;

        private int mPresentPackageCount;
        private int mAllPackageCount;

        private string mInstallLogStr; 

        private float mLoadProgress = 0;
        private float mLoadAssetsProgress = 0;
        private bool isStartDownLoadInsPackage;
        private bool isStartDownLoadAssetsPackage;

        #endregion

        #region mono mathods
        private void Start()
        {
            ConfigInit();
            UIInit();
        }

        
        private void Update()
        {
            //进度条

            if (isStartDownLoadInsPackage)
            {
                mLoadingSlider.value = mLoadProgress;
                mInstallLogStr = string.Concat("正在下载安装包，请稍后... ", ProgressTurnPercent(mLoadProgress));
            }

            if (isStartDownLoadAssetsPackage)
            {
                mLoadingSlider.value = mLoadAssetsProgress;
                mInstallLogStr = string.Concat("正在下载资源包，请稍后... ", ProgressTurnPercent(mLoadAssetsProgress), " (" + mPresentPackageCount + "/" + mAllPackageCount + ")");
            }

            if (mInstallLoadingPanel.gameObject.activeInHierarchy)
            {
                mInstallText.text = mInstallLogStr;
            }
        }

        private void ConfigInit()
        {
            //拿到本地配置信息
            mConfigData = LocalConfigOperate.ReadConfig();
            //拿到局域网配置信息
            StartCoroutine(WebReadAndDownLoad.Instance.GetVersionConfigByWeb(mConfigData.URL, config =>
            {
                mWebConfigData = config; 
                //Start
                StartCoroutine(StartProcedure());
            }));
        }

        private void UIInit()
        {
            Transform canvas = GameObject.Find("Canvas").transform;

            mLoadingPanel = canvas.Find("LoadingPanel").transform;
            mLoadingText = canvas.Find("LoadingPanel/Text").GetComponent<Text>();
            mInstallPanel = canvas.Find("DownLoadingPanel").transform;
            mSelectUrlPanel = mInstallPanel.Find("UrlSelect");
            mInstallLoadingPanel = mInstallPanel.Find("InstallLoading");
            mInstallBtn = mSelectUrlPanel.Find("InstallBtn").GetComponent<Button>();
            mChangeUrlBtn = mSelectUrlPanel.Find("ChangeUrl").GetComponent<Button>();
            mUrlText = mSelectUrlPanel.Find("URLImage/URLText").GetComponent<Text>();
            mLoadingSlider = mInstallLoadingPanel.Find("Slider").GetComponent<Slider>();
            mInstallText = mInstallLoadingPanel.Find("Text").GetComponent<Text>();

            if (SetDefaultRootUrl()) { mUrlText.text = mConfigData.LocalRootURL; }
        }

        private void OnDestroy()
        {
            WebReadAndDownLoad.Instance.threadDownLoad.ForceStopThread();
        }

        private void OnApplicationQuit()
        {
            WebReadAndDownLoad.Instance.threadDownLoad.ForceStopThread();
        }
        #endregion

        #region  private mathods
        private IEnumerator StartProcedure()
        {
            //TODO: 这里的逻辑是可以优化的。逻辑: 先判断本地是否有安装，没有就走安装流程。有安装过就再判断是否有更新，有更新就更新，没更新就启动。
            //逻辑够简单，但是会有很多重复的代码
            //还有代码里面的路径也是需要优化的

            if (TryGetInitiator())
            {

                LoadState = LoadingState.Version;
                bool versiongJudege = string.Equals(mConfigData.Version, mWebConfigData.Version);

                yield return new WaitForSeconds(1f);

                //查看版本信息是否需要更新
                if (versiongJudege)
                {
                    LoadState = LoadingState.Open;
                    yield return new WaitForSeconds(1f);
                    //不要更新直接启动
                    OpenInstallPackageQuitThisProcedure();
                }
                else
                {
                    //需要更新，开始更新
                    LoadState = LoadingState.Update;
                    AssetsUpdate();
                }
            }
            else
            {
                //没有就开始下载安装包和资源包
                LoadState = LoadingState.Download;
                Install();
            }
        }

        private void Install()
        {
            mLoadingPanel.gameObject.SetActive(false);
            mInstallPanel.gameObject.SetActive(true);

            mChangeUrlBtn.onClick.AddListener(() =>
            {
                //拿到选择的文件夹路径
                mLocalRootUrl = WindowsForms.GetDir();
                mUrlText.text = mLocalRootUrl;
            });


            mInstallBtn.onClick.AddListener(() =>
            {
                mSelectUrlPanel.gameObject.SetActive(false);
                mInstallLoadingPanel.gameObject.SetActive(true);

                string rootPath = string.IsNullOrEmpty(mLocalRootUrl) ? mConfigData.LocalRootURL : mLocalRootUrl;
                rootPath = rootPath.Replace(@"\", "/");
                //安装路径
                string installPath = string.Concat(rootPath, mConfigData.InstallPackageUrl);
                //下载路径
                string downloadPath = string.Concat(mWebConfigData.WebUrlRoot, mWebConfigData.InstallPackageUrl);

                string fileName = mWebConfigData.PackageName;

                //更新配置文件默认本地文件
                mConfigData.LocalRootURL = rootPath;
                LocalConfigOperate.UpdateConfig(mConfigData);

                //开始下载
                isStartDownLoadInsPackage = true;
                WebReadAndDownLoad.Instance.DownLoadZipAssetThread(downloadPath, fileName, installPath, loadProgress => { mLoadProgress = loadProgress; }, () =>
                {
                    isStartDownLoadInsPackage = false;
                    mInstallLogStr = "安装包下载完成!正在解压...";
                }, () =>
                 {
                     mInstallLogStr = "安装包解压完成!开始校验资源包...";
                     DownLoadStreamingAssets();
                 });
            });
        }

        //下载资源包
        private void DownLoadStreamingAssets()
        {
            string rootPath = string.IsNullOrEmpty(mLocalRootUrl) ? mConfigData.LocalRootURL : mLocalRootUrl;
            rootPath = rootPath.Replace(@"\", "/");

            string installPath = string.Concat(rootPath, mConfigData.StreamingAssetsUrl);
            string downloadPath = string.Concat(mWebConfigData.WebUrlRoot, mWebConfigData.StreamingAssetsUrl);

            isStartDownLoadAssetsPackage = true;
            WebReadAndDownLoad.Instance.DownLoadAllZipAssetByWeb(downloadPath, installPath, (float progress, int presentCount, int allCount) =>
              {
                  mLoadAssetsProgress = progress;
                  mPresentPackageCount = presentCount;
                  mAllPackageCount = allCount;

              }, () =>
              {
                  isStartDownLoadAssetsPackage = false;
                  mInstallLogStr = "资源包下载完成!正在解压...";
              }, () =>
              {
                  mInstallLogStr = "资源包解压完成!正在启动...";
                  OpenInstallPackageQuitThisProcedure();
              });
        }

        List<AssetsDictionary> needUpdateList;
        List<string> needUpdateAssetsList;

  
        //更新
        private void AssetsUpdate()
        {
            mLoadingPanel.gameObject.SetActive(false);
            mInstallPanel.gameObject.SetActive(true);
            mSelectUrlPanel.gameObject.SetActive(false);
            mInstallLoadingPanel.gameObject.SetActive(true);
          
             VerifyMD5GetUpdateList();

            //安装包是否需要更新
            if (JudgeInstallPackageIsUpdate(needUpdateList))
            {
                string rootPath = mConfigData.LocalRootURL;
                rootPath = rootPath.Replace(@"\", "/");
                string installPath = string.Concat(rootPath, mConfigData.InstallPackageUrl);
                string downloadPath = string.Concat(mWebConfigData.WebUrlRoot, mWebConfigData.InstallPackageUrl);
                string fileName = mWebConfigData.PackageName;
              
                Directory.Delete(installPath,true);
              
                isStartDownLoadInsPackage = true;
                WebReadAndDownLoad.Instance.DownLoadZipAssetThread(downloadPath, fileName, installPath, loadProgress => { mLoadProgress = loadProgress; }, () =>
                {
                  
                    isStartDownLoadInsPackage = false;

                    mInstallLogStr = "安装包下载完成!开始解压...";
                }, () =>
                {
                   
                    mInstallLogStr = "安装包解压完成!开始校验资源包...";
                    UpdateAssetsPackage();
                });
            }
            else
            {
                UpdateAssetsPackage();
            }
        }

       
        private void UpdateAssetsPackage()
        {
            //资源没有更新的内容就直接启动
            if (needUpdateAssetsList.Count == 0)
            {
                UpdateConfigJson();
                OpenInstallPackageQuitThisProcedure();
                return;
            }

            string rootPath = string.IsNullOrEmpty(mLocalRootUrl) ? mConfigData.LocalRootURL : mLocalRootUrl;
            rootPath = rootPath.Replace(@"\", "/");
            string installPath = string.Concat(rootPath, mConfigData.StreamingAssetsUrl);
            string downloadPath = string.Concat(mWebConfigData.WebUrlRoot, mWebConfigData.StreamingAssetsUrl);

            isStartDownLoadAssetsPackage = true;
            WebReadAndDownLoad.Instance.UpdateAssetsPackage(downloadPath, needUpdateAssetsList.ToArray(), installPath, (float progress, int presentCount, int allCount) =>
            {
                mLoadAssetsProgress = progress;
                mPresentPackageCount = presentCount;
                mAllPackageCount = allCount;

            }, () =>
            {
                isStartDownLoadAssetsPackage = false;
                mInstallLogStr = "资源包下载完成!正在解压...";
            }, () =>
            {
                mInstallLogStr = "资源包解压完成!正在启动...";

                UpdateConfigJson();
                OpenInstallPackageQuitThisProcedure();
            });
        }

        //更新完成 修改配置文件的数据
        void UpdateConfigJson()
        {
            mConfigData.StreamAssetsList = mWebConfigData.StreamAssetsList;
            mConfigData.Version = mWebConfigData.Version;
            LocalConfigOperate.UpdateConfig(mConfigData);
        }

        //根据md5值来搜索需要更新的文件   TODO:这个步骤本来想放到更新之前，从局域网和本地获得md5值，然后自动比较，但是获得md5值花费的时间比较久，所以这里直接比                                      较资源的配置文件md5是否相等来判断。这导致修改完了文件，都要去修改配置文件的版本号，还有更新文件的md5。后面需要优                                      化。
        private void VerifyMD5GetUpdateList()
        {
            List<AssetsDictionary> updateList = new List<AssetsDictionary>();
            List<string> assetsUpdateList = new List<string>();


            List<AssetsDictionary> localList = mConfigData.StreamAssetsList;
            List<AssetsDictionary> webList = mWebConfigData.StreamAssetsList;

            for (int i = 0; i < localList.Count; i++)
            {
                for (int j = 0; j < webList.Count; j++)
                {
                    if (localList[i].Path == webList[j].Path)
                    {
                        if (localList[i].Version!=webList[j].Version)
                        {
                            updateList.Add(localList[i]);
                            break; 
                        }
                    }
                }
            }

            updateList.ForEach(item => assetsUpdateList.Add(item.Path));

            string adItem = null;

            foreach (var item in assetsUpdateList)
            {
                if (item.Contains("CreatParty.zip"))
                {
                    adItem = item;
                }
            }

            assetsUpdateList.Remove(adItem);

            needUpdateList = updateList;
            needUpdateAssetsList = assetsUpdateList;

            needUpdateList.ForEach(item => { Debug.Log(item.Path); });

            Debug.Log("-------------------");

            needUpdateAssetsList.ForEach(item => { Debug.Log(item); });
        }
        
        private bool JudgeInstallPackageIsUpdate(List<AssetsDictionary> list)
        {
            foreach (var item in list)
            {
                if (item.Path.Contains("CreatParty.zip"))
                {
                    return true;
                }
            }

            return false;
        }

        //启动安装文件
        private void OpenInstallPackageQuitThisProcedure()
        {
            StartCoroutine(WaitCompressFinishOpenPackage());
        }

        IEnumerator WaitCompressFinishOpenPackage()
        {
            yield return new WaitForSeconds(1f);

            string exePath = string.Concat(mConfigData.LocalRootURL, mConfigData.InstallPackageUrl, "/", mConfigData.ExeName);

            ProcessStartInfo start = new ProcessStartInfo(exePath);
            //start.Arguments = argument;
            start.CreateNoWindow = false;
            start.ErrorDialog = true;
            start.UseShellExecute = true;

            if (start.UseShellExecute)
            {
                start.RedirectStandardOutput = false;
                start.RedirectStandardError = false;
                start.RedirectStandardInput = false;
            }
            else
            {
                start.RedirectStandardOutput = true;
                start.RedirectStandardError = true;
                start.RedirectStandardInput = true;
                start.StandardOutputEncoding = System.Text.UTF8Encoding.UTF8;
                start.StandardErrorEncoding = System.Text.UTF8Encoding.UTF8;
            }

            Process p = Process.Start(start);

            StartCoroutine(QuitThisProcedure());
        }

        //退出当前程序
        IEnumerator QuitThisProcedure()
        {
            yield return new WaitForSeconds(1f);
            UnityEngine.Application.Quit();
        }

        //默认F盘，没有的话修改成D盘  TODO: 这里配置文件的默认值可以修改，然后去掉这个判断
        private bool SetDefaultRootUrl()
        {
            string defaultUrl = mConfigData.LocalRootURL;
            string newUrl = "D:/CreatParty";

            if (defaultUrl.Contains("/"))
            {
                if (!Directory.Exists(defaultUrl.Split('/')[0]))
                {
                    defaultUrl = newUrl;
                }
            }
            else
            {
                if (!Directory.Exists(defaultUrl))
                {
                    defaultUrl = newUrl;
                }
            }

            mConfigData.LocalRootURL = defaultUrl;

            return true;
        }

        //判断有没有党建的启动文件    
        private bool TryGetInitiator()
        {
            string installPath = string.Concat(mConfigData.LocalRootURL, mConfigData.InstallPackageUrl);

            if (Directory.Exists(installPath))
            {
                string exePath = string.Concat(installPath, "/", mConfigData.ExeName);

                if (File.Exists(exePath))
                {
                    return true;
                }
            }
            return false;
        }

        //修改成百分比
        private string ProgressTurnPercent(float progress)
        {
            return string.Concat((int)Mathf.Round(progress * 100), "%");
        }

        private void UpdateVersionCount()
        {
            mConfigData.Version = mWebConfigData.Version;
            LocalConfigOperate.UpdateConfig(mConfigData);
        }
        #endregion

        #region  test mathods

        private void ToLocalJsonTest()
        {
            LocalConfigData data = new LocalConfigData();

            data.Version = "V1.0";
            data.URL = "http://192.168.21.200:90/UnityAssets/CreatParty/config.json";
            data.LocalRootURL = "F:/_Test";
            data.ExeName = "CreatParty.exe";
            data.InstallPackageUrl = "/Install";
            data.AssetBundlsUrl = "/AssetBundles";
            data.StreamingAssetsUrl = "/StreamingAssets";

            data.AssetBundleList = new List<AssetsDictionary>();
            data.AssetBundleList.Add(new AssetsDictionary("CreatParty.assetbundle", "V1.0"));
            data.AssetBundleList.Add(new AssetsDictionary("Cube.assetbundle", "V1.0"));

            data.StreamAssetsList = new List<AssetsDictionary>();
            data.StreamAssetsList.Add(new AssetsDictionary("Bg.mp3", "V1.0"));
            data.StreamAssetsList.Add(new AssetsDictionary("kangjiyiqing.mp4", "V1.0"));

            LocalConfigOperate.UpdateConfig(data);

            Debug.Log("写入完成!");
        }

        private void ToWebJsonTest()
        {
            WebConfigData data = new WebConfigData();

            data.Version = "V1.0";
            data.WebUrlRoot = "http://192.168.21.200:90/UnityAssets/CreatParty";
            data.PackageName = "CreatParty.zip";
            data.InstallPackageUrl = "/Install";
            data.AssetBundlsUrl = "/AssetBundles";
            data.StreamingAssetsUrl = "/StreamingAssets";

            data.AssetBundleList = new List<AssetsDictionary>();
            data.AssetBundleList.Add(new AssetsDictionary("CreatParty.assetbundle", "V1.0"));
            data.AssetBundleList.Add(new AssetsDictionary("Cube.assetbundle", "V1.0"));

            data.StreamAssetsList = new List<AssetsDictionary>();
            data.StreamAssetsList.Add(new AssetsDictionary("Bg.mp3", "V1.0"));
            data.StreamAssetsList.Add(new AssetsDictionary("kangjiyiqing.mp4", "V1.0"));

        }

        #endregion 

    }
}